Tenka1 Programmer Contest

Atcoder题目质量不错啊


C

显然最大值/最小值在最中间,然后贪心的放数字最优。


D


E

题意

二维平面给出 $n$ 个点, 问满足三元组中两两曼哈顿距离相等的数量。

题解

  • 首先需要把曼哈顿距离转化为切比雪夫距离。
  • 然后暴力枚举在同一列 $x$ 和同一行 $y$ 找另一个即可。
  • 二维前缀和优化计数。
  • 重复的只可能的满足 $x$ 和 $y$ 的,两个算一个即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1000+110;

int H, W;
vector<int>r[maxn], c[maxn];
int sum[maxn][maxn];
ll ans;
char s[maxn][maxn];

int solve1(int x,int y1, int y2)
{
if(x<1 || x>H+W) return 0;
return sum[x][y2]-sum[x-1][y2]-sum[x][y1-1]+sum[x-1][y1-1];
}

int solve2(int y, int x1, int x2)
{
if(y<1 || y>H+W) return 0;
if(x1>x2) return 0;
return sum[x2][y] - sum[x1 - 1][y] - sum[x2][y - 1] + sum[x1 - 1][y - 1];
}

int main()
{
scanf("%d%d", &H, &W);
for(int i=1;i<=H;i++)
{
scanf("%s", s[i]+1);
for(int j=1;j<=W;j++)
{
if(s[i][j]=='#')
{
sum[i+j][i-j+W]++;
r[i+j].push_back(i-j+W);
c[i-j+W].push_back(i+j);
}
}
}
for(int i=1;i<=H+W;i++)
{
for(int j=1;j<=H+W;j++)
{
sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
}
}
ll ans=0;
for(int i=1;i<=H+W;i++)
{
sort(r[i].begin(), r[i].end());
for(int j=0;j<int(r[i].size());j++)
{
for(int k=j+1; k<int(r[i].size());k++)
{
int l=r[i][k]-r[i][j];
ans += solve1(i-l, r[i][j], r[i][k]);
ans += solve1(i+l, r[i][j], r[i][k]);
}
}
}
for(int i=1;i<=H+W;i++)
{
sort(c[i].begin(), c[i].end());
for(int j=0;j<int(c[i].size());j++)
{
for(int k=j+1;k<int(c[i].size());k++)
{
int l=c[i][k]-c[i][j];
ans += solve2(i-l, c[i][j]+1, c[i][k]-1);
ans += solve2(i+l, c[i][j]+1, c[i][k]-1);
}
}
}
printf("%lld\n", ans);

}